package com.szeldon.declatest.exec.plugins.jms;

import java.util.logging.Logger;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueReceiver;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

/**
 * Class responsible for checking content of requests received in {@link #onMessage(Message)} invocation and sending
 * response.
 * 
 * @author szeldon
 * 
 */
public class TestMessageListener implements MessageListener {

    private static final Logger logger = Logger.getLogger(TestMessageListener.class.getName());

    // execution parameters
    private String serverUrl;
    private String destinationName;
    private String expectedRequestContent;
    private String responseContent;

    // execution results
    private boolean testEnded = false;
    private boolean testPassed = false;
    private String testResultDescription;
    private String receivedRequest;

    private QueueConnection queueConnection;

    /**
     * Creates an object that will receive message in {@link MessageListener#onMessage(Message)} method. Received
     * message will be compared with given expectedRequestContent (if provided). After receiving (with before-mentioned
     * optional checking) there will be response sent to given serverUrl on given destination name with given
     * responseContent. This thing is also optional.
     * 
     * @param serverUrl
     *            If null, no response will be send.
     * @param destinationName
     *            Can't be null if serverUrl isn't null.
     * @param expectedRequestContent
     *            If null, received request won't be checked for equality.
     * @param responseContent
     *            Can't be null if serverUrl isn't null.
     */
    public TestMessageListener(String serverUrl, String destinationName, String expectedRequestContent,
            String responseContent) {
        this.serverUrl = serverUrl;
        this.destinationName = destinationName;
        this.expectedRequestContent = expectedRequestContent;
        this.responseContent = responseContent;
    }

    @Override
    public void onMessage(Message message) {
        if (message == null) {
            return;
        }
        try {
            String messageContent = ((TextMessage) message).getText();
            logger.fine("Received message (" + message + ") in tester.");

            // optional request checking
            if (expectedRequestContent != null) {
                if (messageContent.equals(expectedRequestContent)) {
                    logger.fine("Received message equals to the expected one.");
                    testPassed = true;
                } else {
                    logger.fine("Received message doesn't equal to the expected one.");
                    testResultDescription = "Received request isn't equal with expected one.";
                    receivedRequest = messageContent;
                }
            }

            // optional response sending
            if (serverUrl != null && testPassed == true) {
                logger.fine("Sending response.");
                sendTestResponse(serverUrl, destinationName, responseContent);
            }
            queueConnection.close();
            logger.fine("Handling message in TestMessageListener ends.");

            testEnded = true;
        } catch (JMSException e) {
            e.printStackTrace();
        } catch (NamingException e) {
            e.printStackTrace();
        }
    }

    /**
     * 
     * @param queueName
     * @param receivingFromServerUrl
     * @throws JMSException
     * @throws NamingException
     */
    public void start(String queueName, String receivingFromServerUrl) throws JMSException, NamingException {
        logger.fine("Creating context for test request on queue: " + queueName + " on server: "
                + receivingFromServerUrl);
        Context jndiContext = new InitialContext();
        jndiContext.addToEnvironment(Context.INITIAL_CONTEXT_FACTORY,
                "org.apache.activemq.jndi.ActiveMQInitialContextFactory");
        jndiContext.addToEnvironment(Context.PROVIDER_URL, receivingFromServerUrl);
        logger.fine("Looking up queue connection factory for test request.");
        QueueConnectionFactory queueConnectionFactory = (QueueConnectionFactory) jndiContext
                .lookup("QueueConnectionFactory");
        logger.finest("Creating queue connection for test request.");
        queueConnection = queueConnectionFactory.createQueueConnection();
        logger.finest("Creating queue session for test request.");
        QueueSession session = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
        logger.finest("Creating queue (" + queueName + ") for test request.");
        Queue queue = session.createQueue(queueName);
        logger.finest("Creating queue receiver for test request.");
        QueueReceiver receiver = session.createReceiver(queue);
        logger.finest("Setting queue listner for test request.");
        receiver.setMessageListener(this);
        logger.finest("Connecting to queue for test request.");
        queueConnection.start();
    }

    /**
     * 
     * @param serverUrl
     * @param destinationName
     * @param responseContent
     * @throws JMSException
     * @throws NamingException
     */
    private void sendTestResponse(String serverUrl, String destinationName, String responseContent)
            throws JMSException, NamingException {
        logger.fine("Creating context for test response.");
        Context jndiContext = new InitialContext();
        jndiContext.addToEnvironment(Context.INITIAL_CONTEXT_FACTORY,
                "org.apache.activemq.jndi.ActiveMQInitialContextFactory");
        jndiContext.addToEnvironment(Context.PROVIDER_URL, serverUrl);
        logger.fine("Looking up queue connection factory for test response.");
        QueueConnectionFactory queueConnectionFactory = (QueueConnectionFactory) jndiContext
                .lookup("QueueConnectionFactory");
        logger.finest("Looking up queue for test response: " + destinationName);
        Queue queue = (Queue) jndiContext.lookup(destinationName);
        logger.finest("Creating queue connection for test response.");
        QueueConnection queueConnection = queueConnectionFactory.createQueueConnection();
        logger.finest("Starting queue connection for test response.");
        queueConnection.start();
        logger.finest("Creating queue session for test response.");
        QueueSession queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
        logger.finest("Creating queue sender for test response.");
        QueueSender queueSender = queueSession.createSender(queue);
        logger.finest("Creating text message for test response.");
        TextMessage textMessage = queueSession.createTextMessage(responseContent);
        logger.finest("Sending text message for test response.");
        queueSender.send(textMessage);
    }

    public static Logger getLogger() {
        return logger;
    }

    public String getServerUrl() {
        return serverUrl;
    }

    public String getDestinationName() {
        return destinationName;
    }

    public String getExpectedRequestContent() {
        return expectedRequestContent;
    }

    public String getResponseContent() {
        return responseContent;
    }

    public boolean isTestPassed() {
        return testPassed;
    }

    public String getTestResultDescription() {
        return testResultDescription;
    }

    public String getReceivedRequest() {
        return receivedRequest;
    }

    public boolean isTestEnded() {
        return testEnded;
    }

}